<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 数组
        topEnv.array = (...values) => values;
        topEnv.length = array => array.length;
        topEnv.element = (array, i) => array[i];
        run(`
            do(define(sum, fun(array,
                do(define(i, 0),
                    define(sum, 0),
                    while(<(i, length(array)),
                    do(define(sum, +(sum, element(array, i))),
                        define(i, +(i, 1)))),
                    sum))),
            print(sum(array(1, 2, 3))))
            `);// → 6



        // 注释
        function skipSpace(string) {
            let skippable = string.match(/^(\s|#.*)*/);
            return string.slice(skippable[0].length);
        }

        console.log(parse("# hello\nx"));  // → {type: "word", name: "x"}


        console.log(parse("a # one\n   # two\n()")); // → {type: "apply",operator: {type: "word", name: "a"},args: []}


        // 修复作用域

        specialForms.set = (args, env) => {
            if (args.length != 2 || args[0].type != "word") {
                throw new SyntaxError("Bad use of set");
            }
            let varName = args[0].name;
            let value = evaluate(args[1], env);

            for (let scope = env; scope; scope = Object.getPrototypeOf(scope)) {
                if (Object.prototype.hasOwnProperty.call(scope, varName)) {
                    scope[varName] = value;
                    return value;
                }
            }
            throw new ReferenceError(`Setting undefined variable ${varName}`);
        };

        run(`
            do(define(x, 4),
            define(setx, fun(val, set(x, val))),
            setx(50),
            print(x))
            `);
        run(`set(quux, true)`);
    </script>
</body>

</html>